package com.maysham.tripod.dao;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.repository.support.PageableExecutionUtils;

import javax.annotation.Resource;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

public class BaseDao<T> {
    @Resource
    MongoTemplate template;
    private Class<T> clazz;
    public BaseDao() {
        clazz = getModelClass();
    }

    protected Page<T> pageQuery(Criteria criteria, Pageable pageable) {
        long count = template.count(Query.query(criteria), clazz);
        if (count == 0) {
            return Page.empty(pageable);
        }
        AggregationResults<T> aggregate = template.aggregate(Aggregation.newAggregation(Aggregation.match(criteria),
                Aggregation.skip((pageable.getPageNumber() - 1L) * pageable.getPageSize()),
                Aggregation.limit(pageable.getPageSize())), clazz, clazz);
        List<T> results = aggregate.getMappedResults();
        return PageableExecutionUtils.getPage(results, pageable, () -> count);
    }

    private Class<T> getModelClass() {
        Type type = this.getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            Type[] types = ((ParameterizedType) type).getActualTypeArguments();
            if (types == null || types.length != 1) {
                throw new RuntimeException("");
            }
            return (Class<T>) types[0];
        } else {
            throw new RuntimeException("");
        }
    }

    public T findById(String id) {
        return template.findOne(Query.query(Criteria.where("id").is(id).and("deleted").is(false)), clazz);
    }

    public boolean existById(String id) {
        return template.exists(Query.query(Criteria.where("id").is(id).and("deleted").is(false)), clazz);
    }

    public T insert(T t) {
        return template.insert(t);
    }
}
